#include "ShapeDef.h"
#include "Stream.h"
#include "LightAbstractRenderer.h"
#include "SceneObject.h"


namespace LightPlayer{


	SHAPERECORD::SHAPERECORD(){
		init();
	}

	void SHAPERECORD::init(){
		m_TypeRecord = eEndShapeRecord;
		m_StateNewStyles = false;
		m_StateLineStyle = false;
		m_StateFillStyle1 = false;
		m_StateFillStyle0 = false;
		m_StateMoveTo = false;
		m_general_line_flag = false;
		m_vertical_line_flag = false;
		m_FillStyle0 = 0;
		m_FillStyle1 = 0;
		m_LineStyle = 0;
		m_MoveDeltaX = 0;
		m_MoveDeltaY = 0;
	}

	void SHAPERECORD::readFromStream( Stream* stream, int tag_shape, 
														int& number_fill_bits, int& number_line_bits, 
														int& offset_fill_index, int& offset_line_index, 
														FILLSTYLEARRAY* fillStyles, LINESTYLEARRAY* lineStyles )
	{
		init();
		
		bool EdgeRecord = stream->read_bool();
		if(!EdgeRecord){
			m_StateNewStyles = stream->read_bool();
			m_StateLineStyle = stream->read_bool();
			m_StateFillStyle1 = stream->read_bool();
			m_StateFillStyle0 = stream->read_bool();
			m_StateMoveTo = stream->read_bool();

			if( m_StateNewStyles == false && m_StateLineStyle == false && m_StateFillStyle1 == false && m_StateFillStyle0 == false && m_StateMoveTo == false ){
				m_TypeRecord = eEndShapeRecord;
			} else {
				m_TypeRecord = eStyleChangeRecord;

				if(m_StateMoveTo){
					int number_move_bits = stream->read_uint(5);
					m_MoveDeltaX = TWIPS_TO_PIXELS( (float) stream->read_sint(number_move_bits) );
					m_MoveDeltaY = TWIPS_TO_PIXELS( (float) stream->read_sint(number_move_bits) );
				}
				if(m_StateFillStyle0){
					m_FillStyle0 = stream->read_uint(number_fill_bits) + offset_fill_index;
				}
				if(m_StateFillStyle1){
					m_FillStyle1 = stream->read_uint(number_fill_bits) + offset_fill_index;
				}
				if(m_StateLineStyle){
					m_LineStyle = stream->read_uint(number_line_bits) + offset_line_index;
				}
				if(m_StateNewStyles){

					if(fillStyles){
						offset_fill_index = fillStyles->m_FillStyles.size();
						fillStyles->addFromStream(stream,tag_shape);
					}
					else{
						FILLSTYLEARRAY newFillStyles;
						newFillStyles.readFromStream(stream,tag_shape);
					}

					if( lineStyles ){
						offset_line_index = lineStyles->m_LineStyles2.size();
						lineStyles->addFromStream(stream,tag_shape);
					}
					else{
						LINESTYLEARRAY newLineStyles;
						newLineStyles.readFromStream(stream,tag_shape);
					}

					number_fill_bits = stream->read_uint(4);
					number_line_bits = stream->read_uint(4);
					
					//assert(0);
					// what should I do with this new FILLSTYLEARRAY & LINESTYLEARRAY & fill_bits & line_bits !!!!
				}
			}
		}
		else{ 
			bool staight_flag = stream->read_bool();
			if(staight_flag){
				m_TypeRecord = eStraightEdgeRecord;

				int number_move_bits = stream->read_uint(4);

				m_general_line_flag = stream->read_bool();
				m_vertical_line_flag = false;
				if(!m_general_line_flag){
					m_vertical_line_flag = stream->read_bool();
				}

				if( m_general_line_flag || !m_vertical_line_flag){
					m_MoveDeltaX = TWIPS_TO_PIXELS( (float) stream->read_sint(number_move_bits + 2) );
				}

				if( m_general_line_flag || m_vertical_line_flag){
					m_MoveDeltaY = TWIPS_TO_PIXELS( (float) stream->read_sint(number_move_bits + 2) );
				}

			} else {
				m_TypeRecord = eCurvedEdgeRecord;
			
				int number_move_bits = stream->read_uint(4);

				m_ControlDeltaX = TWIPS_TO_PIXELS( (float) stream->read_sint(number_move_bits + 2) );
				m_ControlDeltaY = TWIPS_TO_PIXELS( (float) stream->read_sint(number_move_bits + 2) );
				m_AnchorDeltaX =  TWIPS_TO_PIXELS( (float) stream->read_sint(number_move_bits + 2) );
				m_AnchorDeltaY =  TWIPS_TO_PIXELS( (float) stream->read_sint(number_move_bits + 2) );
			}
		}
	}

	SHAPE_NOSTYLE::SHAPE_NOSTYLE()	{
		init();
	}

	void SHAPE_NOSTYLE::init(){
		m_ShapeRecords.clear();
	}

	void SHAPE_NOSTYLE::readFromStream( Stream* stream, int tag_shape /*= eDefineShape*/ ){
		init();

		int num_fill_bits = stream->read_uint(4);
		int num_line_bits = stream->read_uint(4);

		int offset_fill_style_index = 0;
		int offset_line_style_index = 0;

		bool endLoop = false;
		while (!endLoop){
			SHAPERECORD record;
			record.readFromStream(stream, tag_shape,num_fill_bits,num_line_bits, offset_fill_style_index, offset_line_style_index, NULL, NULL );
			if(record.m_TypeRecord == eEndShapeRecord){
				endLoop = true;
			} else {
				m_ShapeRecords.push_back(record);
			}
		}
	}


	SHAPE_WITHSTYLE::SHAPE_WITHSTYLE(){
		init();
	}

	void SHAPE_WITHSTYLE::init(){
		m_FillStyles.init();
		m_LineStyles.init();
		m_ShapeRecords.clear();
	}

	void SHAPE_WITHSTYLE::readFromStream( Stream* stream, int tag_shape /*= eDefineShape*/, bool is_font_glyph /*= false*/ ){
		init();
		
		if( !is_font_glyph ){
			m_FillStyles.readFromStream(stream,tag_shape);
			m_LineStyles.readFromStream(stream,tag_shape);
		}
		
		int num_fill_bits = stream->read_uint(4);
		int num_line_bits = stream->read_uint(4);

		int offset_fill_style_index = 0;
		int offset_line_style_index = 0;

		bool endLoop = false;
		while (!endLoop){
			SHAPERECORD record;
			record.readFromStream(stream, tag_shape,num_fill_bits,num_line_bits,offset_fill_style_index, offset_line_style_index, &m_FillStyles, &m_LineStyles );
			if(record.m_TypeRecord == eEndShapeRecord){
				endLoop = true;
			} else {
				m_ShapeRecords.push_back(record);
			}
		}
	}


	SHAPE_DEFINITION::SHAPE_DEFINITION(){
		init();
	}

	void SHAPE_DEFINITION::init(){
		m_CharacterId = 0;
		m_ShapeBounds = RECT();
		m_EdgeBounds = RECT();
		m_UseFillWindingRule = false;
		m_UsesNonScalingStrokes = false;
		m_UsesScalingStrokes = false;
		m_ShapeWithStyle.init();
	}

	void SHAPE_DEFINITION::readFromStream( Stream* stream, int tag_shape /*= eDefineShape*/, bool is_font_glyph /*= false*/ ){
		init();
		
		if( !is_font_glyph ){
			m_ShapeBounds.readFromStream(stream);
		}

		if(tag_shape == eDefineShape4){
			m_EdgeBounds.readFromStream(stream);
			int skip = stream->read_uint(5);
			m_UseFillWindingRule = stream->read_bool();
			m_UsesNonScalingStrokes = stream->read_bool();
			m_UsesScalingStrokes = stream->read_bool();
		}

		m_ShapeWithStyle.readFromStream(stream,tag_shape,is_font_glyph);
	}

	void SHAPE_DEFINITION::draw( LightAbstractRenderer* pRenderer, SceneObject* pInstance ){
		
		vec2 drawPos;

		FILLSTYLE* fill_style = NULL;


		int number_record = m_ShapeWithStyle.m_ShapeRecords.size();
		for (int i=0; i<number_record; i++){

			SHAPERECORD* record = &( m_ShapeWithStyle.m_ShapeRecords[i] );
			if( record->m_TypeRecord == eStyleChangeRecord ){
				if( record->m_StateNewStyles ){
					fill_style =  &(m_ShapeWithStyle.m_FillStyles.at( record->m_FillStyle1 ) );
				}
				if( record->m_StateMoveTo ){
					drawPos.set( record->m_MoveDeltaX, record->m_MoveDeltaY );
				}
			}
			else if( record->m_TypeRecord == eStraightEdgeRecord ){

				vec2 nextPos = drawPos;
				if(  record->m_general_line_flag || ! record->m_vertical_line_flag){
					nextPos.x += record->m_MoveDeltaX;
				}
				if(  record->m_general_line_flag ||  record->m_vertical_line_flag){
					nextPos.y += record->m_MoveDeltaY;
				}

				// draw line here 
				pRenderer->DrawLine( drawPos, nextPos );
				// end
				drawPos = nextPos;
			}
			else if( record->m_TypeRecord == eCurvedEdgeRecord ){

				vec2 offCurveControl( drawPos.x + record->m_ControlDeltaX, drawPos.y + record->m_ControlDeltaY );
				vec2 nextPos( offCurveControl.x + record->m_AnchorDeltaX, offCurveControl.y + record->m_AnchorDeltaY );

				// draw bezier curve here 
				pRenderer->DrawQuadBezier( drawPos, offCurveControl, nextPos, 10 );
				// end

				drawPos = nextPos;
			}
		}
	}

};